home *** CD-ROM | disk | FTP | other *** search
/ NOVA - For the NeXT Workstation / NOVA - For the NeXT Workstation.iso / SourceCode / AdobeExamples / NX_Text / rotateprocs.c < prev    next >
Encoding:
Text File  |  1992-12-19  |  6.8 KB  |  275 lines

  1.  
  2. /*
  3.  * (a)  (C) 1990 by Adobe Systems Incorporated. All rights reserved.
  4.  *
  5.  * (b)  If this Sample Code is distributed as part of the Display PostScript
  6.  *    System Software Development Kit from Adobe Systems Incorporated,
  7.  *    then this copy is designated as Development Software and its use is
  8.  *    subject to the terms of the License Agreement attached to such Kit.
  9.  *
  10.  * (c)  If this Sample Code is distributed independently, then the following
  11.  *    terms apply:
  12.  *
  13.  * (d)  This file may be freely copied and redistributed as long as:
  14.  *    1) Parts (a), (d), (e) and (f) continue to be included in the file,
  15.  *    2) If the file has been modified in any way, a notice of such
  16.  *      modification is conspicuously indicated.
  17.  *
  18.  * (e)  PostScript, Display PostScript, and Adobe are registered trademarks of
  19.  *    Adobe Systems Incorporated.
  20.  * 
  21.  * (f) THE INFORMATION BELOW IS FURNISHED AS IS, IS SUBJECT TO
  22.  *    CHANGE WITHOUT NOTICE, AND SHOULD NOT BE CONSTRUED
  23.  *    AS A COMMITMENT BY ADOBE SYSTEMS INCORPORATED.
  24.  *    ADOBE SYSTEMS INCORPORATED ASSUMES NO RESPONSIBILITY
  25.  *    OR LIABILITY FOR ANY ERRORS OR INACCURACIES, MAKES NO
  26.  *    WARRANTY OF ANY KIND (EXPRESS, IMPLIED OR STATUTORY)
  27.  *    WITH RESPECT TO THIS INFORMATION, AND EXPRESSLY
  28.  *    DISCLAIMS ANY AND ALL WARRANTIES OF MERCHANTABILITY, 
  29.  *    FITNESS FOR PARTICULAR PURPOSES AND NONINFRINGEMENT
  30.  *    OF THIRD PARTY RIGHTS.
  31.  */
  32.  
  33. /*
  34.  *    rotateprocs.c
  35.  *
  36.  *    This file contains procedure that perform operations
  37.  *    on rotated rectangles and points.
  38.  *
  39.  *    Note: the angle in the procedures below should be expressed
  40.  *    in radians and not degrees.
  41.  *
  42.  *    Version:    2.0
  43.  *    Author:    Ken Fromm
  44.  *    History:
  45.  *            03-07-91        Added this comment.
  46.  */
  47.  
  48. #import <appkit/graphics.h>
  49. #import <appkit/nextstd.h>
  50. #import <math.h>
  51.  
  52. /*
  53. *    Takes the point passed in, rotates it around the point
  54. *    at the angle given and returns the new point.
  55. *    The new point replaces the old one and its address
  56. *    is returned as the return value.
  57. */
  58. NXPoint *RotatePoint(NXPoint *aPoint, NXPoint *cPoint, float angle)
  59. {
  60.     float        d, dx, dy;
  61.  
  62.     float        ang;
  63.  
  64.     if (aPoint && cPoint && angle != 0)
  65.     {
  66.         dx = aPoint->x - cPoint->x;
  67.         dy = aPoint->y - cPoint->y;
  68.  
  69.         *aPoint = *cPoint;
  70.         d = sqrt(dx * dx + dy * dy);
  71.         if (d != 0.0)
  72.         {
  73.             ang = angle + (float) atan2(dy, dx);
  74.             aPoint->x += d * cos(ang);
  75.             aPoint->y += d * sin(ang);
  76.         }
  77.     }
  78.  
  79.     return aPoint;
  80. }
  81.  
  82. /*
  83. *    Checks whether the point passed in lies in the rectangle
  84. *    rotated about its lower left vertice at the angle provided.
  85. *    Returns either YES or NO. Assumes an unflipped 
  86. *    coordinate system.
  87. */
  88. BOOL MouseInRotatedRect(NXPoint *aPoint, NXRect *aRect, float angle)
  89. {
  90.     NXPoint        pt;
  91.  
  92.     if (aRect && aPoint)
  93.     {
  94.         pt = *aPoint;
  95.         RotatePoint(&pt, &aRect->origin, -angle);
  96.  
  97.         return NXMouseInRect(&pt, aRect, NO);
  98.     }
  99.     else
  100.         return NO;
  101. }
  102.  
  103. /*
  104. *    This procedure takes the unrotated rectangle, bRect,
  105. *    rotates it around the point, cPoint, at the angle, angle,
  106. *    and places the new bounding box that encloses the
  107. *    rotated rectangle in the rectangle aRect. The address
  108. *    of the new rectangle is returned as the return value.
  109. *
  110. *    Figuring the new width and height is relatively
  111. *    straight-forward. Just take the sin and cos of  the
  112. *    old width and height.
  113. *
  114. *    Figuring the new origin is a bit different. The vertices
  115. *    for the lower x and lower y coordinates are chosen
  116. *    based on the angle to rotate. Their positions in the rotated
  117. *    spaced are calculated and subtracted from the center point.
  118. */
  119. NXRect *RotateRectBounds(NXRect *aRect, const NXRect *bRect, NXPoint *cPoint, float angle)
  120. {
  121.     float            dx, dy, dxx, dxy, dyx, dyy;
  122.  
  123.     double        cosa, sina;
  124.     
  125.     if (aRect  && bRect && cPoint)
  126.     {
  127.         if (angle != 0)
  128.         {
  129.             cosa = cos(angle);
  130.             sina = sin(angle);
  131.  
  132.             dyx = dxx = bRect->origin.x - cPoint->x;
  133.             dyy = dxy = bRect->origin.y - cPoint->y;
  134.  
  135.             if (cosa > 0)
  136.             {
  137.                 if (sina > 0)
  138.                     dxy += bRect->size.height;
  139.                 else
  140.                     dyx += bRect->size.width;        
  141.             }
  142.             else
  143.             {
  144.                 if (sina > 0)
  145.                 {
  146.                     dxx += bRect->size.width;
  147.                     dyy = dxy = dxy + bRect->size.height;
  148.                 }
  149.                 else
  150.                 {
  151.                     dyx = dxx = dxx + bRect->size.width;
  152.                     dyy += bRect->size.height; 
  153.                 }
  154.             }
  155.  
  156.             aRect->origin = *cPoint;
  157.  
  158.             dx = sqrt(dxx * dxx + dxy * dxy);
  159.             if (dx != 0.0)
  160.                 aRect->origin.x += (float) dx * cos(angle + atan2(dxy, dxx));
  161.             dy = sqrt(dyx * dyx + dyy * dyy);
  162.             if (dy != 0.0)
  163.                 aRect->origin.y += (float) dy * sin(angle + atan2(dyy, dyx));
  164.  
  165.             aRect->size.width = (float) (ABS(bRect->size.width * cosa) +
  166.                         ABS(bRect->size.height * sina));
  167.             aRect->size.height = (float) (ABS(bRect->size.width * cos(M_PI_2 - angle)) +
  168.                         ABS(bRect->size.height * sin(M_PI_2 - angle)));
  169.         }
  170.         else
  171.             *aRect = *bRect;
  172.     }
  173.  
  174.     return aRect;
  175. }
  176.  
  177. /*
  178. *    This procedure calculates the minimum hypotense
  179. *    for a width and a height. The width and height are
  180. *    meant to be from different triangles sharing the same
  181. *    angles.
  182. */
  183. static double DistanceToEdge(float x, float y, float angle)
  184. {
  185.     float            dx, dy;
  186.  
  187.     double        cosa, sina;
  188.  
  189.     cosa = cos(angle);
  190.     if (cosa != 0.0)
  191.         dx = ABS(x / cosa);
  192.     else
  193.         dx = y;
  194.  
  195.     sina = sin(angle);
  196.     if (sina != 0.0)
  197.         dy = ABS(y / sina);
  198.     else
  199.         dy = x;
  200.  
  201.     return MIN(dx, dy);
  202. }
  203.  
  204. /*
  205. *    This procedure takes two rectangles and an angle.
  206. *    It checks if the second rectangle rotated about its origin
  207. *    at the given angle intersects the first rectangle. The
  208. *    first rectangle is unrotated. 
  209. *
  210. *    It checks for intersection by comparing the distance between
  211. *    the centers to the sum of the distance from the centers to the
  212. *    edges. If the distance between the centers is less than the
  213. *    sum of the distance to the edges, the rectangles intersect.
  214. */
  215. BOOL IntersectsRotatedRect(NXRect *aRect, NXRect *bRect, float angle)
  216. {
  217.     BOOL    intersect = NO;
  218.  
  219.     float        d, dx, dy, da, db;
  220.  
  221.     float        ang;
  222.     
  223.     NXPoint    bCenter;
  224.  
  225.     if (aRect && bRect)
  226.     {
  227.         if (angle != 0.0)
  228.         {
  229.             bCenter.x = bRect->origin.x + bRect->size.width/2;
  230.             bCenter.y = bRect->origin.y + bRect->size.height/2;
  231.             RotatePoint(&bCenter, &bRect->origin, angle);
  232.  
  233.             dx = bCenter.x - (aRect->origin.x + aRect->size.width/2);
  234.             dy = bCenter.y - (aRect->origin.y + aRect->size.height/2);
  235.             d = sqrt(dx*dx + dy*dy);
  236.             if (d)
  237.             {
  238.                 ang = (float) atan2(dy, dx);
  239.                 da = DistanceToEdge(aRect->size.width/2, aRect->size.height/2, ang);
  240.                 ang = ang + M_PI_2 - angle;
  241.                 db = DistanceToEdge(bRect->size.width/2, bRect->size.height/2, ang);
  242.  
  243.                 intersect = (d <= da + db);
  244.             }
  245.             else
  246.                 intersect = YES;
  247.         }
  248.         else
  249.             intersect = NXIntersectsRect(aRect, bRect);
  250.     }
  251.  
  252.     return intersect;
  253. }
  254.  
  255. /*
  256. *    This procedure takes two points and constrains the first
  257. *    point to the nearest 15% interval.
  258. */
  259. void ConstrainPointToAngle(NXPoint *aPoint, NXPoint *cPoint, float angle)
  260. {
  261.     float        d, dx, dy, a;
  262.  
  263.     dx = aPoint->x - cPoint->x;
  264.     dy = aPoint->y - cPoint->y;
  265.     d = sqrt(dx*dx + dy*dy);
  266.  
  267.     if (d != 0.0)
  268.     {
  269.         a = rint(atan2(dy, dx) / angle) * angle;
  270.         aPoint->x = (float) cPoint->x + d * cos(a);
  271.         aPoint->y = (float) cPoint->y + d * sin(a);
  272.     }
  273. }
  274.  
  275.